﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Diagnostics;
using System.Reflection;

namespace hypervmgmtlib
{
    using msvm = wmi.root.virtualization.msvm;
    using cim = wmi.root.virtualization.cim;

    internal static class util
    {
        public static T CreateObj<T>(object obj)
        {
            return (T) Activator.CreateInstance(typeof (T), obj);
        }

        public static ManagementObject[] GetRelatedObjects(ManagementPath thisObjPath, string relatedClassName,
                                                           string relationshipClassName)
        {
            var qry = new RelatedObjectQuery(thisObjPath.Path, relatedClassName, relationshipClassName, null, null, null,
                                             null, false);
            var searcher = new ManagementObjectSearcher(new ManagementScope(thisObjPath), qry);
            return searcher.Get().Cast<ManagementObject>().ToArray();
        }
    }

    public static class VMMS_
    {
        public static msvm.VirtualSystemManagementService vmmsObj
        {
            get
            {
                return msvm.VirtualSystemManagementService
                    .GetInstances()
                    .Cast<msvm.VirtualSystemManagementService>()
                    .Single();
            }
        }

        public static ManagementPath DefineVirtualSystem(string[] ResourceSettingData, ManagementPath SourceSetting,
                                                         string SystemSettingData)
        {
            ManagementPath DefinedSystem;
            ManagementPath Job;

            uint ret = vmmsObj.DefineVirtualSystem(ResourceSettingData, SourceSetting, SystemSettingData
                                                   , out DefinedSystem, out Job);

            return DefinedSystem;
        }

        //public uint DestroyVirtualSystem(System.Management.ManagementPath ComputerSystem, out System.Management.ManagementPath Job) {
        public static void DestroyVirtualSystem(ManagementPath ComputerSystem)
        {
            ManagementPath Job;
            uint ret = vmmsObj.DestroyVirtualSystem(ComputerSystem, out Job);
        }
    }

    [DebuggerDisplay("VM: {Id} {Name}")]
    public class VM_
    {
        public VM_(msvm.ComputerSystem vmObj)
        {
            this.vmObj = vmObj;
        }

        public msvm.ComputerSystem vmObj { get; private set; }

        public string Id
        {
            get { return vmObj.Name; }
        }

        public string Name
        {
            get { return vmObj.ElementName; }
        }

        public static VM_ Create(string name)
        {
            var settingDataObj = msvm.VirtualSystemGlobalSettingData.CreateInstance();

            settingDataObj.LateBoundObject["ElementName"] = name;
            VMMS_.DefineVirtualSystem(null, new ManagementPath(),
                                      settingDataObj.LateBoundObject.GetText(TextFormat.CimDtd20)
                );

            return null;
        }

        public void Delete()
        {
            VMMS_.DestroyVirtualSystem(vmObj.Path);
        }

        public static VM_[] Get()
        {
            return null;
        }
    }

    public class VMSetting_
    {
        public VMSetting_(msvm.VirtualSystemSettingData settingObj)
        {
            this.settingObj = settingObj;
        }

        public msvm.VirtualSystemSettingData settingObj { get; private set; }

        public static VMSetting_ Get(VM_ vm)
        {
            return null;
        }
    }

    [DebuggerDisplay("Cpu: {Count}")]
    public class Cpu_
    {
        public Cpu_(msvm.ProcessorSettingData cpuObj)
        {
            this.cpuObj = cpuObj;
        }

        public msvm.ProcessorSettingData cpuObj { get; private set; }

        public int Count
        {
            get { return (int) cpuObj.VirtualQuantity; }
            set { }
        }

        public static Cpu_ Get(VMSetting_ vmSetting)
        {
            return null;
        }
    }

    [DebuggerDisplay("Ram: {Startup}")]
    public class Mem_
    {
        public Mem_(msvm.MemorySettingData memObj)
        {
            this.memObj = memObj;
        }

        public msvm.MemorySettingData memObj { get; private set; }

        public int Startup
        {
            get { return (int) memObj.VirtualQuantity; }
            set { }
        }

        public static Mem_ Get(VMSetting_ vmSetting)
        {
            return null;
        }
    }

    public interface IController
    {
    }

    public class Ide_ : IController
    {
        public Ide_(msvm.ResourceAllocationSettingData ideObj)
        {
            this.ideObj = ideObj;
        }

        public msvm.ResourceAllocationSettingData ideObj { get; private set; }

        public static Ide_[] Get(VMSetting_ vmSetting)
        {
            return null;
        }
    }

    public class Scsi_ : IController
    {
        public Scsi_(msvm.ResourceAllocationSettingData scsiObj)
        {
            this.scsiObj = scsiObj;
        }

        public msvm.ResourceAllocationSettingData scsiObj { get; private set; }

        public static Scsi_[] Get(VMSetting_ vmSetting)
        {
            return null;
        }

        public static Scsi_ Create(VM_ vm)
        {
            return null;
        }

        public void Delete()
        {
        }
    }

    public interface IDrive
    {
    }

    public class Hdd_ : IDrive
    {
        public Hdd_(msvm.ResourceAllocationSettingData hddObj)
        {
            this.hddObj = hddObj;
        }

        public msvm.ResourceAllocationSettingData hddObj { get; private set; }

        public static Hdd_[] Get(IController controller)
        {
            return null;
        }

        public static Hdd_ Create(IController controller)
        {
            return null;
        }

        public void Delete()
        {
        }
    }

    public class Dvd_ : IDrive
    {
        public Dvd_(msvm.ResourceAllocationSettingData dvdObj)
        {
            this.dvdObj = dvdObj;
        }

        public msvm.ResourceAllocationSettingData dvdObj { get; private set; }

        public static Dvd_[] Get(IController controller)
        {
            return null;
        }

        public static Dvd_ Create(IController controller)
        {
            return null;
        }

        public void Delete()
        {
        }
    }

    public interface IMedia
    {
    }

    public interface IHdMedia : IMedia
    {
    }

    public interface IDvdMedia : IMedia
    {
    }

    public class VhdImage : IHdMedia
    {
        public VhdImage(msvm.ResourceAllocationSettingData vhdImageObj)
        {
            this.vhdImageObj = vhdImageObj;
        }

        public msvm.ResourceAllocationSettingData vhdImageObj { get; private set; }

        public static VhdImage[] Get(Hdd_ hdd)
        {
            return null;
        }

        public static VhdImage Create(Hdd_ hdd)
        {
            return null;
        }

        public void Delete()
        {
        }
    }

    public class IsoImage : IDvdMedia
    {
        public IsoImage(msvm.ResourceAllocationSettingData isoImageObj)
        {
            this.isoImageObj = isoImageObj;
        }

        public msvm.ResourceAllocationSettingData isoImageObj { get; private set; }

        public static IsoImage[] Get(Dvd_ dvd)
        {
            return null;
        }

        public static IsoImage Create(Dvd_ dvd)
        {
            return null;
        }

        public void Delete()
        {
        }
    }

    public class HdPassthrough : IHdMedia
    {
    }

    public class DvdPassthrough : IDvdMedia
    {
    }
}